package com.example.reggie_take_out.controller;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.example.reggie_take_out.commen.R;
import com.example.reggie_take_out.dto.DishDto;
import com.example.reggie_take_out.entry.Category;
import com.example.reggie_take_out.entry.Dish;
import com.example.reggie_take_out.entry.DishFlavor;
import com.example.reggie_take_out.service.CategoryService;
import com.example.reggie_take_out.service.DishFlavorService;
import com.example.reggie_take_out.service.DishService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CachePut;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;

import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 菜品管理
 */
@RestController
@RequestMapping("/dish")
@Slf4j
public class DishController {

    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private DishService dishService;
    @Autowired
    private DishFlavorService dishFlavorService;

    @Autowired
    private CategoryService categoryService;
    /**
     * 添加菜品数据
     * 由于前端闯过来的json数据中 还有一个json数据 即 Dish中有一个DishFlavor
     * 所以我们要定义个一个新的前后端数据传输类DTO(Data Transfer Object)
     */
    @RequestMapping
    public R<String> save(@RequestBody DishDto dishDto){
        /**
         * 由于这个save要同时将数据保存到Dish表和DishFlavor表
         * 因此我们不能再用mp给我们提供的方法 而事自定义一个方法
         */
        dishService.saveWithFlavor(dishDto);

        /**
         * 当mysql表中数据被操作时 我们应该立马删除redis中的表 防止数据不一致
         */
        /*删除所有的菜品表
        Set keys = redisTemplate.keys("dish_*");
        redisTemplate.delete(keys);*/

        //删除redis中某一部分菜品
        String key = "dish_"+dishDto.getCategoryId()+"_1";
        redisTemplate.delete(key);
        return R.success("新菜品添加成功！");
    }

    /**
     * 分页查询
     * 由于Dish类中没有 菜的类别名这一个属性 所以我们最后要返回的实际上是 DishDto这个类
     * 利用dishService的page创建好分页对象后 将分页对象 拷贝给dtoPageInfo 但是里面的类不考
     * 里面的类需要遍历List<Dish> records 然后将每一个Dish的值拷贝给 DishDto 然后创建List<DishDto>
     *  赋值给dtoPageInfo中的List<DishDto> records
     * @param page
     * @param pageSize
     * @param name
     * @return
     */

    @GetMapping("/page")
    public R<Page> page(int page, int pageSize ,String name){
        Page<Dish> pageInfo = new Page<>(page,pageSize);
        Page<DishDto> dtoPageInfo = new Page<>();
        LambdaQueryWrapper<Dish> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.like(name != null,Dish::getName,name);
        queryWrapper.orderByDesc(Dish::getUpdateTime);
        dishService.page(pageInfo,queryWrapper);
        //将分页信息传给dtoPageInfo
        BeanUtils.copyProperties(pageInfo,dtoPageInfo,"records");

        List<DishDto> list= pageInfo.getRecords().stream().map((item)->{
            //创建一个新的dtoPageInfo对象
            DishDto dishDto = new DishDto();
            //将record中每一个Dish的信息拷贝给每一个 dtoPageInfo
            BeanUtils.copyProperties(item,dishDto);
            //获得record中每一个Dish的信息
            Long categoryId = item.getCategoryId();
            Category category = categoryService.getById(categoryId);
            if(category != null){
                String category_name = category.getName();
                dishDto.setCategoryName(category_name);
            }

            return dishDto;
        }).collect(Collectors.toList());

        //所有信息拷贝完成
        dtoPageInfo.setRecords(list);

        return R.success(dtoPageInfo);

    }

    /**
     * 根据id查询DishDto 由于涉及到两张表的操作 所以不能使用mp提供的方法 需要自定义方法
     * @param id
     * @return
     */

    @GetMapping("/{id}")
    public R<DishDto> get(@PathVariable Long id){

        DishDto dishDto = dishService.selectByIdWithFlavor(id);
        return R.success(dishDto);
    }

    /**
     * 修改菜品信息
     * @param dishDto
     * @return
     */

    @PutMapping
    public R<String> update(@RequestBody DishDto dishDto){
            dishService.updateByIdWithFlavor(dishDto);
            //删除redis中某一部分菜品
            String key = "dish_"+dishDto.getCategoryId()+"_1";
            redisTemplate.delete(key);
            return R.success("商品修改成功");
    }

    /**
     * 修改 status状态
     * @param status
     * @param ids
     * @return
     */
    @PostMapping("/status/{status}")
    @Transactional
    public R<String> status(@PathVariable int status,Long []ids ){
        for (int i = 0; i < ids.length; i++) {
            Dish dish = dishService.getById(ids[i]);
            dish.setStatus(status);
            dishService.updateById(dish);
        }
        return R.success("状态修改成功");
    }

    /**
     * 根据id删除表 注意 删除一个dish表 后 应该也随之删除 他的dishFlavor表
     * @param ids
     * @return
     */
    @DeleteMapping
    @Transactional
    public R<String> delete(Long []ids){
        for (int i = 0; i < ids.length; i++) {
            dishService.deleteByIdWithFlavor(ids[i]);
        }
        return R.success("删除成功");
    }

    /**
     * 根据categoryid查菜品
     * @param dish
     * @return
     */
    /*@GetMapping("/list")
    public R<List<Dish>> list(Dish dish){
        Long categoryId = dish.getCategoryId();

        LambdaQueryWrapper<Dish> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(categoryId!= null ,Dish::getCategoryId,categoryId);
        queryWrapper.eq(Dish::getStatus,1);
        queryWrapper.orderByAsc(Dish::getSort).orderByDesc(Dish::getUpdateTime);
        List<Dish> list = dishService.list(queryWrapper);
        return R.success(list);

    }*/

    /**
     * 满足前端代码 复用 将返回类型由List<Dish> 改为List<DishDto> 且不改变原先的功能
     * @param dish
     * @return
     */
    @GetMapping("/list")
    public R<List<DishDto>> list(Dish dish){
        //加入redis后 不用每次请求都去访问 数据库 如果在高并发的情况下会对数据库造成很大影响 从而影响性能
        //因此 我们可以先 查看缓存中有有无此次要访问的数据 如果有 则直接返回缓存中的数据
        //如果没有 则从数据库中查找数据 并加入缓存中后返回
        Long categoryId = dish.getCategoryId();
        Integer status = dish.getStatus();

        List<DishDto> dishDtoList = null;
        //动态创建redis中的key
        String key = "key_"+categoryId+"_"+status;
        dishDtoList = (List<DishDto>)redisTemplate.opsForValue().get(key);
        if(dishDtoList != null){
            //如果redis中 含有该数据 则直接返回
            redisTemplate.expire(key, 10, TimeUnit.MINUTES);//更新缓存的时间
            return R.success(dishDtoList);
        }

        //如果redis中没有 那么进行查询

        LambdaQueryWrapper<Dish> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(categoryId!= null ,Dish::getCategoryId,categoryId);
        queryWrapper.eq(Dish::getStatus,1);
        queryWrapper.orderByAsc(Dish::getSort).orderByDesc(Dish::getUpdateTime);
        List<Dish> list = dishService.list(queryWrapper);
        //将list<Dish> 赋值给 list<DishDto>
            dishDtoList = list.stream().map((item)->{
            DishDto dishDto = new DishDto();
            BeanUtils.copyProperties(item,dishDto);
            Long id = dishDto.getId();
            LambdaQueryWrapper<DishFlavor> queryWrapper1 = new LambdaQueryWrapper<>();
            queryWrapper1.eq(DishFlavor::getDishId,id);
            List<DishFlavor> list1 = dishFlavorService.list(queryWrapper1);
            dishDto.setFlavors(list1);
            return dishDto;
        }).collect(Collectors.toList());

         //查询完成之后 把数据还要存入redis中
        redisTemplate.opsForValue().set(key,dishDtoList,10,TimeUnit.MINUTES);

        return R.success(dishDtoList);

    }


}
